// retry-strategy.ts

/**
 * 重试策略配置项
 */
export interface RetryPolicyOptions {
    maxRetries?: number; // 最大重试次数 (默认 5)
    initialDelay?: number; // 初始延迟时间 (ms) (默认 1000)
    maxDelay?: number; // 最大延迟时间 (ms) (默认 30000)
    jitter?: boolean; // 是否启用随机抖动 (默认 true)
    factor?: number; // 指数因子 (默认 2)
}

/**
 * 重试策略计算结果
 */
export interface RetryResult {
    delay: number; // 当前延迟时间
    retriesLeft: number; // 剩余重试次数
    shouldRetry: boolean; // 是否应该继续重试
}

/**
 * 指数退避 + 随机抖动策略计算器
 */
export class RetryPolicy {
    private readonly options: Required<RetryPolicyOptions>;

    constructor(options: RetryPolicyOptions = {}) {
        this.options = {
            maxRetries: 5,
            initialDelay: 1000,
            maxDelay: 10000,
            jitter: true,
            factor: 2,
            ...options
        };
    }

    /**
     * 计算下一次重试参数
     * @param retriesAttempted 已尝试次数
     * @returns 重试策略结果
     */
    calculate(retriesAttempted: number): RetryResult {
        const { maxRetries, initialDelay, maxDelay, factor, jitter } = this.options;

        // 检查是否达到最大重试次数
        if (retriesAttempted >= maxRetries) {
            return {
                delay: 0,
                retriesLeft: 0,
                shouldRetry: false
            };
        }

        // 计算指数退避
        const exponent = Math.min(retriesAttempted, 30); // 防止数值溢出
        let delay = initialDelay * Math.pow(factor, exponent);

        // 应用最大延迟限制
        delay = Math.min(delay, maxDelay);

        // 添加随机抖动
        if (jitter) {
            const jitterAmount = delay * Math.random() * 0.5; // ±50% 抖动
            delay += retriesAttempted % 2 === 0 ? jitterAmount : -jitterAmount;
        }

        return {
            delay: Math.max(delay, initialDelay),
            retriesLeft: maxRetries - retriesAttempted - 1,
            shouldRetry: true
        };
    }
}
